package com.zhengqiangblog.blog.service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.log4j.Logger;

import com.zhengqiangblog.blog.cache.ArticleCache;
import com.zhengqiangblog.blog.cache.ArticleTagCache;
import com.zhengqiangblog.blog.cache.CategoryCache;
import com.zhengqiangblog.blog.cache.TagCache;
import com.zhengqiangblog.blog.exception.ResourceNotFoundException;
import com.zhengqiangblog.blog.model.Archive;
import com.zhengqiangblog.blog.model.Article;
import com.zhengqiangblog.blog.model.ArticleTag;
import com.zhengqiangblog.blog.model.Category;
import com.zhengqiangblog.blog.model.Tag;
import com.zhengqiangblog.core.ApplicationContext;

public class ArticleService {

	private static final Logger logger = Logger.getLogger(ArticleService.class);

	private ArticleCache articleCache = ApplicationContext.get(ArticleCache.class);
	private CategoryCache categoryCache = ApplicationContext.get(CategoryCache.class);
	private ArticleTagCache articleTagCache = ApplicationContext.get(ArticleTagCache.class);
	private TagCache tagCache = ApplicationContext.get(TagCache.class);

	public ArticleService() {
		logger.info("ArticleService initializing...");
	}

	private ConcurrentHashMap<Integer, AtomicLong> viewsMap = new ConcurrentHashMap<Integer, AtomicLong>();

	public int saveArticle(Article article) throws Exception {
		return articleCache.saveArticle(article);
	}

	public Article getArticle(int articleId) throws Exception {
		Article article = articleCache.getArticle(articleId);
		if (article != null) {
			Category category = categoryCache.getCategory(article.getCategoryId());
			article.setCategory(category);
			List<ArticleTag> articleTagList = articleTagCache.getArticleTagByArticle(articleId);
			List<Tag> tags = new ArrayList<Tag>();
			for (int i = 0; i < articleTagList.size(); i++) {
				ArticleTag articleTag = articleTagList.get(i);
				int tagId = articleTag.getTagId();
				Tag tag = tagCache.getTag(tagId);
				tags.add(tag);
			}
			article.setTags(tags);
		}
		return article;
	}

	public Article getArticleAndIncreseViews(int articleId) throws Exception {
		Article article = this.getArticle(articleId);
		if (article != null) {
			viewsMap.putIfAbsent(article.getId(), new AtomicLong(article.getViews()));
			AtomicLong views = viewsMap.get(article.getId());
			article.setViews(views.incrementAndGet());
		}
		return article;
	}

	public void persistArticleViews() throws Exception {
		List<Integer> ids = this.getArticleIdList();
		for (int i = 0; i < ids.size(); i++) {
			int id = ids.get(i);
			Article article = this.getArticle(id);
			if (article != null) {
				this.updateArticleViews(id, article.getViews());
			}
		}
	}

	public int updateArticleViews(int id, long views) throws Exception {
		return articleCache.updateArticleViews(id, views);
	}

	public List<Article> getArticleList(int start, int size) throws Exception {
		List<Article> articleList = new ArrayList<Article>();
		List<Integer> articleIdList = this.getArticleIdList();
		int end = start + size;
		if (end > articleIdList.size()) {
			end = articleIdList.size();
		}
		List<Integer> pageList = articleIdList.subList(start, end);
		for (int i = 0; i < pageList.size(); i++) {
			int articleId = pageList.get(i);
			Article article = this.getArticle(articleId);
			articleList.add(article);
		}
		return articleList;
	}

	public List<Integer> getArticleIdList() throws Exception {
		return articleCache.getArticleIdList();
	}

	public List<Article> getArticleListByCategory(int categoryId, int start, int size) throws Exception {
		List<Article> articleList = new ArrayList<Article>();
		List<Integer> articleIdList = this.getArticleIdListByCategory(categoryId);
		int end = start + size;
		if (end > articleIdList.size()) {
			end = articleIdList.size();
		}
		List<Integer> pageList = articleIdList.subList(start, end);
		for (int i = 0; i < pageList.size(); i++) {
			int articleId = pageList.get(i);
			Article article = this.getArticle(articleId);
			articleList.add(article);
		}
		return articleList;
	}

	public List<Integer> getArticleIdListByCategory(int categoryId) throws Exception {
		return articleCache.getArticleIdListByCategory(categoryId);
	}

	public List<Archive> getArchives() throws Exception {
		return articleCache.getArchives();
	}

	public List<Integer> getArticleIdListByDate(int year, int month) throws Exception {
		return articleCache.getArticleIdListByDate(year, month);
	}

	public List<Article> getArticleListByDate(int year, int month, int start, int size) throws Exception {
		List<Article> articleList = new ArrayList<Article>();
		List<Integer> articleIdList = this.getArticleIdListByDate(year, month);
		int end = start + size;
		if (end > articleIdList.size()) {
			end = articleIdList.size();
		}
		List<Integer> pageList = articleIdList.subList(start, end);
		for (int i = 0; i < pageList.size(); i++) {
			int articleId = pageList.get(i);
			Article article = this.getArticle(articleId);
			articleList.add(article);
		}
		return articleList;
	}

	public List<Integer> getArticleIdListByTag(String tagName) throws Exception {
		Tag tag = tagCache.getTagByName(tagName);
		if (tag == null) {
			throw new ResourceNotFoundException();
		}
		int tagId = tag.getId();
		return articleTagCache.getArticleIdListByTagId(tagId);
	}

	public List<Article> getArticleListByTag(String tagName, int start, int size) throws Exception {
		List<Article> articleList = new ArrayList<Article>();
		List<Integer> articleIdList = this.getArticleIdListByTag(tagName);
		int end = start + size;
		if (end > articleIdList.size()) {
			end = articleIdList.size();
		}
		List<Integer> pageList = articleIdList.subList(start, end);
		for (int i = 0; i < pageList.size(); i++) {
			int articleId = pageList.get(i);
			Article article = this.getArticle(articleId);
			articleList.add(article);
		}
		return articleList;
	}

	public int updateArticleStatus(int articleId, int status) throws Exception {
		return articleCache.updateArticleStatus(articleId, status);
	}

	public int updateArticle(Article article) throws Exception {
		return articleCache.updateArticle(article);
	}

	public int deleteArticle(int articleId) throws Exception {
		return articleCache.deleteArticle(articleId);
	}

}
